#define _BSD_SOURCE

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include "tlpi.h"
#include <sys/types.h>

#define PORT_NUM "50000"
#define BACK_LOG 32
#define BUF_SIZE 1024

int
main(int argc, char *argv[])
{
	int svfd, clfd;
	struct addrinfo hints;
	struct addrinfo *result, *cur;
	int optval;
	struct sockaddr_storage claddr;
	socklen_t addrlen;
	char host[NI_MAXHOST], service[NI_MAXSERV];
	char buf[BUF_SIZE];
	ssize_t numRead;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	if(getaddrinfo(NULL, PORT_NUM, &hints, &result) == -1)
		errExit("getaddrinfo() failed");

	optval = 1;
	for(cur = result; cur != NULL; cur = cur->ai_next)
	{
		if((svfd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol)) == -1)
			continue;

		if(setsockopt(svfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1)
		{
			freeaddrinfo(result);
			close(svfd);
			errExit("setsockopt() failed");
		}

		if(bind(svfd, cur->ai_addr, cur->ai_addrlen) == 0)
			break;

		close(svfd);
	}

	if(cur == NULL)
		fatal("svfd can not bind any address\n");

	if(listen(svfd, BACK_LOG) == -1)
		errExit("listen() failed");

	for(;;)
	{
		addrlen = sizeof(struct sockaddr_storage);
		if((clfd = accept(svfd, (struct sockaddr *)&claddr, &addrlen)) == -1)
		{
			fprintf(stderr, "accept() failed\n");
			continue;
		}

		if(getnameinfo((struct sockaddr *)&claddr, addrlen, host, NI_MAXHOST,
					service, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) == 0)
			printf("connect from (%s, %s)\n", host, service);
		else
			printf("connect from ?UNKOWN?\n");

		while((numRead = read(clfd, buf, BUF_SIZE)) > 0)
		{
			if(write(clfd, buf, numRead) != numRead)
			{
				fprintf(stderr, "write() failed\n");
				break;
			}
		}
	}
}
